import time
import os
import csv

from application.config import appSettings as config
from application.config import DB
from application.http.models import CodeModel
from sanren.extensions import MyLogger


class AbolishJob:
    """
        作废码 任务类
    """

    # 作废码单信息
    obj_info = None

    # init
    def __init__(self, params):
        self.log = MyLogger('abolish')
        self.params = params

    # 打印 log
    def info(self, msg):
        self.log.logger.info(msg)
        print(msg)

    """
        作废码
    """
    def run(self):
        start_time = time.time()

        # 作废
        self.obj_info = CodeModel.Abolish.where('id', self.params['id']).first()
        if self.obj_info is None:
            self.info('Abolish Code: 找不到此作废单')

        # 作废单状态
        if self.obj_info.status not in (0, 1, 4):
            self.info('Abolish Code: 已经成功或取消的作废单不能再进行作废操作')

        # 开始作废
        try:
            # 作废
            self.info('==========================作废信息开始========================')
            self.info('Abolish Code: 正式开始作废，batch_sn:' + self.obj_info.batch_sn)

            # 码表
            company_code = self.obj_info.company_code
            Code = CodeModel.get_code_model(company_code)

            # 写入数据
            self.info('==========================开始写数据库========================')

            # scope_status 1 整批作废 2 部分作废
            if self.obj_info.scope_status == 1:
                # 整批作废
                # 作废码量
                self.obj_info.counts = Code.where('batch_sn', self.obj_info.batch_sn).count()

                # status 0 未启用 1 启用 2 禁用
                Code.where('batch_sn', self.obj_info.batch_sn).update({'status': 2})

            elif self.obj_info.scope_status == 2:
                # 部分作废 读取文件
                abolish_file_path = os.path.join(config.upload_path, self.obj_info.scope_file)
                abolish_codes = []
                with open(abolish_file_path, encoding='utf-8') as f:
                    reader = csv.reader(f)
                    [abolish_codes.append(row[0]) for row in reader if row]

                    # 作废码量
                    self.obj_info.counts = len(set(abolish_codes))

                    print(set(abolish_codes))

                    # 所有指定禁用码
                    # 执行 禁用操作
                    code_update = Code.where('batch_sn', self.obj_info.batch_sn)
                    if self.obj_info.scope_type == 1:
                        code_update = code_update.where_in('small_code', set(abolish_codes))
                    elif self.obj_info.scope_type == 2:
                        code_update = code_update.where_in('security_code', set(abolish_codes))
                    else:
                        raise Exception('部分作废出错')
                    # 作废
                    code_update.update({'status': 2})

            else:
                raise Exception('作废出错')

            self.info('==========================写数据库成功========================')

        except Exception as e:
            # 异常
            DB.session.rollback()
            self.info('==========================出错啦========================')

            # 更新作废状态 为 3 取消 4 错误
            self.obj_info.status = 4
            self.obj_info.error_reason = '写入数据库失败：' + str(e)
            self.obj_info.save()

        else:
            # 如果没有异常发生
            # 更新作废状态 2 完成 done
            self.obj_info.status = 2
            self.obj_info.save()

        self.info('==========================作废信息结束========================')

        process_time = time.time() - start_time
        self.info(f'共用时：{process_time}')

    """
        还原作废码
    """
    def restore(self):
        start_time = time.time()

        # 作废
        self.obj_info = CodeModel.Abolish.where('id', self.params['id']).first()
        if self.obj_info is None:
            self.info('Abolish Code: 找不到此作废单')

        # 作废单状态
        if self.obj_info.status != 2:
            self.info('Abolish Code: 已经成功的作废单才能再进行作废还原操作')

        # 开始作废
        try:
            # 作废
            self.info('==========================作废还原开始========================')
            self.info('Abolish Code: 正式开始还原，batch_sn:' + self.obj_info.batch_sn)

            # 码表
            company_code = self.obj_info.company_code
            Code = CodeModel.get_code_model(company_code)

            # 写入数据
            self.info('==========================开始写数据库========================')

            # scope_status 1 整批作废 2 部分作废
            if self.obj_info.scope_status == 1:
                # 整批作废
                # 作废码量 还原后更新为 0
                self.obj_info.counts = 0

                # status 0 未启用 1 启用 2 禁用
                Code.where('batch_sn', self.obj_info.batch_sn).update({'status': 1})

            elif self.obj_info.scope_status == 2:
                # 部分作废 读取文件
                abolish_file_path = os.path.join(config.upload_path, self.obj_info.scope_file)
                abolish_codes = []
                with open(abolish_file_path, encoding='utf-8') as f:
                    reader = csv.reader(f)
                    [abolish_codes.append(row[0]) for row in reader if row]

                    # 所有指定禁用码
                    # 执行 禁用操作
                    code_update = Code.where('batch_sn', self.obj_info.batch_sn)
                    if self.obj_info.scope_type == 1:
                        code_update = code_update.where_in('small_code', set(abolish_codes))
                    elif self.obj_info.scope_type == 2:
                        code_update = code_update.where_in('security_code', set(abolish_codes))
                    else:
                        raise Exception('部分作废出错')
                    # 启用
                    code_update.update({'status': 1})

            else:
                raise Exception('作废出错')

            self.info('==========================写数据库成功========================')

            # raise Exception('测试出错') # 测试事务
        except Exception as e:
            # 异常
            DB.session.rollback()
            self.info('==========================出错啦========================')

            # 更新作废状态 为 3 取消 4 错误
            self.obj_info.status = 4
            self.obj_info.error_reason = str(e)
            self.obj_info.save()

        else:
            # 如果没有异常发生
            # 更新作废状态 3 取消 restore
            self.obj_info.status = 3
            self.obj_info.save()

        self.info('==========================作废还原结束========================')

        process_time = time.time() - start_time
        self.info(f'共用时：{process_time}')
